<?php
/**
 * Created by PhpStorm
 * User: Jhinwy
 * Date: 8/8/24
 * Time: 6:04 PM
 */

namespace app\common\service\wechat;

use app\common\model\app\App;
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;
use think\facade\Cache;
use think\facade\Log;
use think\File;

class WechatService
{

    const CACHE_WECHAT_MINI_PROGRAM_ACCESS_TOKEN = 'wechat_mini_program_access_token_';


    protected static $host = 'https://api.weixin.qq.com/';

    protected static $headers = ['Content-Type' => 'application/json'];


    // token
    protected static $accessTokenUri = 'cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s';
    // 拉取上传
    protected static $pullUploadUri = 'wxa/sec/vod/pullupload?access_token=%s';
    // 查询任务
    protected static $getTaskUri = 'wxa/sec/vod/gettask?access_token=%s';
    // 剧目提审
    protected static $auditDramaUri = 'wxa/sec/vod/auditdrama?access_token=%s';
    // 媒资列表
    protected static $mediaListUri = 'wxa/sec/vod/listmedia?access_token=%s';
    // 删除媒资
    protected static $deleteMediaUri = 'wxa/sec/vod/deletemedia?access_token=%s';
    // 上传媒体素材
    protected static $mediaUploadUri = 'cgi-bin/media/upload?access_token=%s&type=%s';
    // 获取临时素材
    protected static $getMediaUri = 'cgi-bin/media/get?access_token=%s&media_id=%s';
    // 剧目提审详情
    protected static $getDramaUri = 'wxa/sec/vod/getdrama?access_token=%s';


    /**
     * 获取微信小程序授权token
     *
     * @param $id
     * @return bool
     * @throws \GuzzleHttp\Exception\GuzzleException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getAccessToken($id)
    {
        try {
            $app       = App::find($id);
            $appId     = $app->app_id ?? '';
            $appSecret = $app->app_secret ?? '';
            if ($accessToken = Cache::get(self::CACHE_WECHAT_MINI_PROGRAM_ACCESS_TOKEN . $appId)) {

                return $accessToken;
            }
            $client   = new Client();
            $response = $client->get(sprintf(self::formatUrl(self::$accessTokenUri), $appId, $appSecret));
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            $data     = json_decode($contents, true);

            $accessToken = $data['access_token'] ?? '';
            $expiresIn   = $data['expires_in'] ?? 0;
            if (!$accessToken || !$expiresIn) {
                throw new \Exception('token信息不存在');
            }
            Cache::set(self::CACHE_WECHAT_MINI_PROGRAM_ACCESS_TOKEN . $appId, $accessToken, $expiresIn);

            return $accessToken;
        } catch (\Exception $exception) {
            Log::write('获取微信小程序Access Token失败：' . $exception->getMessage());

            return false;
        }
    }


    /**
     * 拉取上传视频
     *
     * @param $appId
     * @param $mediaName
     * @param $mediaUrl
     * @param string $coverUrl
     * @return bool|string
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function pullUpload($appId, $mediaName, $mediaUrl, $coverUrl = '')
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $data     = [
                'media_name' => $mediaName,
                'media_url'  => $mediaUrl,
                'cover_url'  => $coverUrl
            ];
            $client   = new Client();
            $response = $client->post(
                sprintf(self::formatUrl(self::$pullUploadUri), $accessToken),
                self::formatData($data)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            $result   = json_decode($contents, true);
            if (($result['errcode'] ?? -1) != 0) {
                throw new \Exception($data['errmsg'] ?? '请求异常');
            }
            $taskId = $result['task_id'] ?? '';

            return true;
        } catch (\Exception $exception) {
            Log::write('拉取上传视频失败：' . $exception->getMessage(), 'error');

            return false;
        }
    }


    /**
     * 获取上传任务
     *
     * @param $appId
     * @param $taskId
     * @return bool
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function getTask($appId, $taskId)
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $data     = [
                'task_id' => $taskId
            ];
            $client   = new Client();
            $response = $client->post(
                sprintf(self::formatUrl(self::$getTaskUri), $accessToken),
                self::formatData($data)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            $result   = json_decode($contents, true);
            if (($result['errcode'] ?? -1) != 0) {
                throw new \Exception($data['errmsg'] ?? '请求异常');
            }

            $taskInfo = $result['task_info'] ?? '';
            return true;
        } catch (\Exception $exception) {
            Log::write('拉取上传视频失败：' . $exception->getMessage(), 'error');

            return false;
        }
    }


    /**
     * 删除媒资
     *
     * @param $appId
     * @param $mediaId
     * @return bool
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function deleteMedia($appId, $mediaId)
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $data     = [
                'media_id' => $mediaId
            ];
            $client   = new Client();
            $response = $client->post(
                sprintf(self::formatUrl(self::$deleteMediaUri), $accessToken),
                self::formatData($data)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            $result   = json_decode($contents, true);
            if (($result['errcode'] ?? -1) != 0) {
                throw new \Exception($data['errmsg'] ?? '请求异常');
            }

            return true;
        } catch (\Exception $exception) {
            Log::write('删除媒资视频失败：' . $exception->getMessage(), 'error');

            return false;
        }
    }


    /**
     * 剧目提审
     *
     * @param $params
     * @return bool|string
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function auditDrama($params)
    {
        try {
            $appId = $params['app_id'] ?? '';
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $dramaId           = $params['drama_id'] ?? '';
            $qualificationType = (int)$params['qualification_type'] ?? 2;
            $data              = [
                'name'                   => $params['name'] ?? '',
                'media_count'            => $params['media_count'] ?? 0,
                'media_id_list'          => $params['media_id_list'] ?? [],
                'description'            => $params['description'] ?? '',
                'recommendations'        => $params['recommendations'] ?? '',
                'cover_material_id'      => $params['cover_material_id'] ?? '',
                'producer'               => $params['producer'] ?? '',
                'authorized_material_id' => $params['authorized_material_id'] ?? '',
                'qualification_type'     => $qualificationType,
                'expedited'              => $params['expedited'] ?? 0,
                'actor_list'             => ['actor' => $params['actor_list'] ?? []],
            ];
            if ($dramaId) {
                $data['drama_id'] = $dramaId;
            }
            if ($qualificationType == 1) {
                $data['registration_number']                   = $params['registration_number'];
                $data['qualification_certificate_material_id'] = $params['qualification_certificate_material_id'];
            }
            if ($qualificationType == 2) {
                $data['cost_of_production']                 = $params['cost_of_production'];
                $data['cost_commitment_letter_material_id'] = $params['cost_commitment_letter_material_id'];
            }
            $client   = new Client();
            $response = $client->post(
                sprintf(self::formatUrl(self::$auditDramaUri), $accessToken),
                self::formatData($data)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            $result   = json_decode($contents, true);

            if (($result['errcode'] ?? -1) != 0) {
                throw new \Exception($data['errmsg'] ?? '请求异常');
            }
            $dramaId = $result['drama_id'] ?? '';

            return $dramaId;
        } catch (\Exception $exception) {
            Log::write('剧目提审失败：' . $exception->getMessage(), 'error');

            return false;
        }
    }


    /**
     * 获取剧目提审信息
     *
     * @param $appId
     * @param $dramaId
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function getDrama($appId, $dramaId)
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            $client   = new Client();
            $response = $client->post(
                sprintf(self::formatUrl(self::$getDramaUri), $accessToken),
                self::formatData(['drama_id' => $dramaId])
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            $result   = json_decode($contents, true);

            if (($result['errcode'] ?? -1) != 0) {
                throw new \Exception($data['errmsg'] ?? '请求异常');
            }
            return $result['drama_info'] ?? [];

        } catch (\Exception $exception) {
            Log::write('剧目提审失败：' . $exception->getMessage(), 'error');

            return [];
        }
    }


    /**
     * 获取媒资列表
     *
     * @param $params
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function getMediaList($params)
    {
        try {
            $appId = $params['app_id'] ?? '';
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }
            if (!$mediaName = $params['media_name'] ?? '') {

                return [];
            }
            $data     = [
                'media_name' => $mediaName . '%',
                'offset'     => $params['offset'] ?? 0,
                'limit'      => $params['page_size'] ?? 10
            ];
            $client   = new Client();
            $response = $client->post(
                sprintf(self::formatUrl(self::$mediaListUri), $accessToken),
                self::formatData($data)
            );
            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            $result   = json_decode($contents, true);
            if (($result['errcode'] ?? -1) != 0) {
                throw new \Exception($data['errmsg'] ?? '请求异常');
            }
            $list = $result['media_info_list'] ?? [];

            return $list;
        } catch (\Exception $exception) {
            Log::write('获取媒资列表失败：' . $exception->getMessage(), 'error');

            return [];
        }
    }


    /**
     * 获取临时素材
     *
     * @param $appId
     * @param $mediaId
     * @return bool|string
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function getMedia($appId, $mediaId)
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }

            return sprintf(self::formatUrl(self::$getMediaUri), $accessToken, $mediaId);
        } catch (\Exception $exception) {
            Log::write('上传临时素材失败：' . $exception->getMessage(), 'error');

            return false;
        }
    }


    /**
     * 上传临时素材
     *
     * @param $appId
     * @param $file
     * @param string $type
     * @return bool|string
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function uploadMedia($appId, $file, $type = 'image')
    {
        try {
            if (!$accessToken = self::getAccessToken($appId)) {
                throw new \Exception('token不存在');
            }

            $client   = new Client();
            $response = $client->post(
                sprintf(self::formatUrl(self::$mediaUploadUri), $accessToken, $type),
                self::formatUploadData($file)
            );

            if ($response->getStatusCode() != 200) {
                throw new \Exception('请求失败！');
            }
            $contents = $response->getBody()->getContents();
            $result   = json_decode($contents, true);
            if (!$mediaId = $result['media_id'] ?? '') {

                return false;
            }

            return $mediaId;
        } catch (\Exception $exception) {
            Log::write('上传临时素材失败：' . $exception->getMessage(), 'error');

            return false;
        }
    }


    /**
     * 格式化数据
     *
     * @param $data
     * @return array
     */
    protected static function formatData($data)
    {
        return [
            'headers' => self::$headers,
            'body'    => json_encode($data, JSON_UNESCAPED_UNICODE)
        ];
    }


    /**
     * 格式化上传数据
     *
     * @param $data
     * @return array
     */
    protected static function formatUploadData(File $file)
    {
        $filename = $file->getOriginalName();

        return [
            RequestOptions:: MULTIPART => [
                [
                    'headers'  => [
                        'Content-Disposition' => 'form-data; name="image";filename="' . $filename . '"',
                        'Content-Type'        => 'image/png'
                    ],
                    'name'     => $filename,
                    'contents' => file_get_contents($file),
                    'filename' => $filename
                ]
            ]
        ];
    }


    /**
     * 格式化Api
     *
     * @param $uri
     * @return string
     */
    protected static function formatUrl($uri)
    {
        return self::$host . $uri;
    }
}
